using System;
using System.Diagnostics.Contracts;
using System.Linq;

namespace ReactiveCode.Observables
{
    public delegate TResult ObservableFactory<TResult>(IStateDecorator stateDecorator);

    [ContractClass(typeof(IStateDecoratorContract))]
    public interface IStateDecorator
    {
        IObservable<T> Apply<T>(IObservable<T> state);
        IObserver<T> Apply<T>(IObserver<T> state);
    }

    #region Contract for IStateDecorator

    [ContractClassFor(typeof(IStateDecorator))]
    abstract class IStateDecoratorContract : IStateDecorator
    {
        public IObservable<T> Apply<T>(IObservable<T> state)
        {
            Contract.Requires<ArgumentNullException>(state != null, "state");
            Contract.Ensures(Contract.Result<IObservable<T>>() != null);
            throw new NotImplementedException();
        }

        public IObserver<T> Apply<T>(IObserver<T> state)
        {
            Contract.Requires<ArgumentNullException>(state != null, "state");
            Contract.Ensures(Contract.Result<IObserver<T>>() != null);
            throw new NotImplementedException();
        }
    }    
    
    #endregion

    class NullStateDecorator: IStateDecorator
    {
        public static NullStateDecorator Instance = new NullStateDecorator();

        NullStateDecorator() { }

        public IObservable<T> Apply<T>(IObservable<T> state)
        {
            return state;
        }

        public IObserver<T> Apply<T>(IObserver<T> state)
        {
            return state;
        }
    }
}
